// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UIManualTrading.cs" company="Open Trader">
//   Copyright (c) David Denis (david.denis@systemathics.com)
// </copyright>
// <summary>
//   |  Open Trader - The Open Source Systematic Trading Platform
//   |
//   |  This program is free software: you can redistribute it and/or modify
//   |  it under the terms of the GNU General Public License as published by
//   |  the Free Software Foundation, either version 2 of the License, or
//   |  (at your option) any later version.
//   |
//   |  This program is distributed in the hope that it will be useful,
//   |  but WITHOUT ANY WARRANTY; without even the implied warranty of
//   |  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//   |  GNU General Public License for more details.
//   |
//   |  You should have received a copy of the GNU General Public License
//   |  along with this program.  If not, see http://www.gnu.org/licenses
//   |
//   |  Up to date informations about Open Trader can be found at :
//   |    http://opentrader.org
//   |    http://opentrader.codeplex.com
//   |
//   |  For professional services, please visit us at :
//   |    http://www.systemathics.com
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Org.OpenTrader.Framework.Forge.UI.Forms
{
    #region Using Directives

    using System;
    using System.Collections.Generic;

    using Org.OpenTrader.Framework.Enums;
    using Org.OpenTrader.Framework.Events;
    using Org.OpenTrader.Framework.Forge.DataCache;
    using Org.OpenTrader.Framework.Forge.Enums;
    using Org.OpenTrader.Framework.Forge.Events;
    using Org.OpenTrader.Framework.Forge.Interfaces;
    using Org.OpenTrader.Framework.UI.Forms;

    #endregion

    /// <summary>
    /// The ui manual trading.
    /// </summary>
    public partial class UIManualTrading : UIControl
    {
        #region Constants and Fields

        /// <summary>
        /// The instruments.
        /// </summary>
        private readonly IList<IInstrument> instruments = new List<IInstrument>();

        /// <summary>
        /// The instruments expos.
        /// </summary>
        private readonly IDictionary<Guid, UIInstrumentListExpo> instrumentsExpos = new Dictionary<Guid, UIInstrumentListExpo>();

        /// <summary>
        /// The instruments Market Books.
        /// </summary>
        private readonly IDictionary<Guid, UIMarketBook> instrumentsMarketBooks = new Dictionary<Guid, UIMarketBook>();

        /// <summary>
        /// The instruments Market Fields.
        /// </summary>
        private readonly IDictionary<Guid, UIMarketFieldsCache> instrumentsMarketFields = new Dictionary<Guid, UIMarketFieldsCache>();

        /// <summary>
        /// The instruments trackers.
        /// </summary>
        private readonly IDictionary<Guid, UIOrderTracker> instrumentsTrackers = new Dictionary<Guid, UIOrderTracker>();

        /// <summary>
        /// The referential.
        /// </summary>
        private readonly IReferential referential;

        #endregion

        #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the <see cref="UIManualTrading"/> class.
        /// </summary>
        public UIManualTrading()
        {
            this.InitializeComponent();
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="UIManualTrading"/> class.
        /// </summary>
        /// <param name="dictionaryId">
        /// The dictionary Id.
        /// </param>
        public UIManualTrading(Guid dictionaryId)
        {
            this.InitializeComponent();
            this.referential = Singleton<Universe>.Instance.Referential(this);
            foreach (var instrumentStaticData in Singleton<DC>.Instance.GetInstrumentsStaticDataFromCache(dictionaryId))
            {
                this.comboBoxInstrumentStaticData.Items.Add(new ComboBoxItem(instrumentStaticData));
            }

            //// Singleton<DC>.Instance.DataAccessObjectEventCB += this.OnDataCacheEvent;
        }

        #endregion

        ////private void OnDataCacheEvent(object sender, DataCacheEventArgs e)
        ////{
        ////    if (e is DataCacheEventArgs.CacheModified)
        ////    {
        ////        var args = e as DataCacheEventArgs.CacheModified;
        ////        if (args.Element == EDataCacheElement.Instrument)
        ////        {
        ////            switch (args.Action)
        ////            {
        ////                case EDataCacheAction.Add:
        ////                    var instrumentStaticData = Singleton<DC>.Instance.GetInstrumentStaticDataFromCache(args.ID);
        ////                    if (instrumentStaticData != null)
        ////                    {
        ////                        this.comboBoxInstrumentStaticData.Items.Add(new ComboBoxItem(instrumentStaticData));
        ////                    }
        ////                    break;

        ////                case EDataCacheAction.Remove:
        ////                    ////var instruments = from i in this.comboBoxInstrumentStaticData.Items
        ////                    ////                 where (i as InstrumentStaticData).ID = args.ID
        ////                    ////                 select i;

        ////                    break;

        ////            }
        ////        }
        ////    }
        ////}
        #region Methods

        /// <summary>
        /// The combo box instrument static data_ selected index changed.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void OnComboBoxInstrumentStaticDataSelectedIndexChanged(object sender, EventArgs e)
        {
            var item = this.comboBoxInstrumentStaticData.SelectedItem as ComboBoxItem;
            var status = this.referential.CreateInstrument(item.InstrumentStaticData.Code, item.InstrumentStaticData.TradingScope);
            if (status)
            {
                var instrument = status.NestedObject;
                instrument.InstrumentStaticData.PropertyEventCB += this.OnPropertyEvent;

                if (instrument.InstrumentStaticData.FeedWiring != null)
                {
                    instrument.FeedEventCB += this.OnInstrumentFeedEventCB;
                }

                if (instrument.InstrumentStaticData.OrderWiring != null)
                {
                    instrument.OrderTrackingEventCB += this.OnInstrumentOrderTrackingEventCB;
                }

                this.instruments.Add(instrument);
            }

            this.comboBoxInstrumentStaticData.Items.RemoveAt(this.comboBoxInstrumentStaticData.SelectedIndex);
            this.comboBoxInstrumentStaticData.SelectedIndex = -1;
        }

        /// <summary>
        /// The instrument_ feed event cb.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void OnInstrumentFeedEventCB(object sender, FeedEventArgs e)
        {
        }

        /// <summary>
        /// The instrument_ order tracking event cb.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void OnInstrumentOrderTrackingEventCB(object sender, OrderTrackingEventArgs e)
        {
        }

        /// <summary>
        /// The on property event.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void OnPropertyEvent(object sender, PropertyEventArgs e)
        {
            if (e is PropertyEventArgs.Changed)
            {
                var instrument = sender as IInstrument;
                var args = e as PropertyEventArgs.Changed;
                if (args.PropertyName.Equals("FeedWiring"))
                {
                    if (args.OldValue != null)
                    {
                        instrument.FeedEventCB -= args.OldValue as EventHandler<FeedEventArgs>;
                    }

                    if (args.NewValue != null)
                    {
                        instrument.FeedEventCB += args.NewValue as EventHandler<FeedEventArgs>;
                    }
                }

                // TODO : OrderWiring change means tracker change !
                ////if (args.PropertyName.Equals("OrderWiring"))
                ////{
                ////    if (args.OldValue != null)
                ////    {
                ////        instrument.OrderTracker. -= args.OldValue;
                ////    }

                ////    if (args.NewValue != null)
                ////    {
                ////        instrument.FeedEventCB += args.NewValue;
                ////    }
                ////}
            }
        }

        /// <summary>
        /// The virtual grid instruments_ cell click.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void OnVirtualGridInstrumentsCellClick(object sender, System.Windows.Forms.DataGridViewCellEventArgs e)
        {
            if (e.RowIndex >= this.instruments.Count)
            {
                return;
            }

            var i = this.instruments[e.RowIndex];

            // buttons
            switch (e.ColumnIndex)
            {
                case 3:
                    {
                        // Bid -> Sell
                        var title = string.Format("Sell {0} / {1}", i.InstrumentStaticData.Code, i.InstrumentStaticData.TradingScope);
                        var ctrl = new UIManualOrder(i, UIManualOrder.EManualOrderMode.NewOrderSell);
                        var form = ctrl.CreateContainingForm(title, EUIFormLayoutType.TitleBarAtTop, EUIFormClosingType.Hard);
                        form.Visibility = EUIFormVisibility.Show;
                    }

                    break;

                case 4:
                    {
                        // Ask -> Buy
                        var title = string.Format("Buy {0} / {1}", i.InstrumentStaticData.Code, i.InstrumentStaticData.TradingScope);
                        var ctrl = new UIManualOrder(i, UIManualOrder.EManualOrderMode.NewOrderBuy);
                        var form = ctrl.CreateContainingForm(title, EUIFormLayoutType.TitleBarAtTop, EUIFormClosingType.Hard);
                        form.Visibility = EUIFormVisibility.Show;
                    }

                    break;

                case 8:
                    {
                        // Market Book button
                        if (!this.instrumentsMarketBooks.ContainsKey(i.InstrumentStaticData.ID))
                        {
                            var newuicontrol = new UIMarketBook(i);
                            var uiform =
                                newuicontrol.CreateContainingForm(
                                    string.Format("{0} / {1}", i.InstrumentStaticData.Code, i.InstrumentStaticData.TradingScope), 
                                    EUIFormLayoutType.TitleBarAtTop, 
                                    EUIFormClosingType.Soft);

                            this.instrumentsMarketBooks[i.InstrumentStaticData.ID] = newuicontrol;
                        }

                        var uicontrol = this.instrumentsMarketBooks[i.InstrumentStaticData.ID];
                        uicontrol.ContainingForm.Visibility = EUIFormVisibility.Invert;
                    }

                    break;

                case 9:
                    {
                        // Market Fields button
                        if (!this.instrumentsMarketFields.ContainsKey(i.InstrumentStaticData.ID))
                        {
                            var newuicontrol = new UIMarketFieldsCache(i);
                            var uiform =
                                newuicontrol.CreateContainingForm(
                                    string.Format("{0} / {1}", i.InstrumentStaticData.Code, i.InstrumentStaticData.TradingScope), 
                                    EUIFormLayoutType.TitleBarAtTop, 
                                    EUIFormClosingType.Soft);

                            this.instrumentsMarketFields[i.InstrumentStaticData.ID] = newuicontrol;
                        }

                        var uicontrol = this.instrumentsMarketFields[i.InstrumentStaticData.ID];
                        uicontrol.ContainingForm.Visibility = EUIFormVisibility.Invert;
                    }

                    break;

                case 12:
                    {
                        // I.Expo button
                        if (! this.instrumentsExpos.ContainsKey(i.InstrumentStaticData.ID))
                        {
                            var newuicontrol = new UIInstrumentListExpo();
                            var uiform = newuicontrol.CreateContainingForm(
                                string.Format("Expositions for {0}", i.InstrumentStaticData.FriendlyName), 
                                EUIFormLayoutType.TitleBarAtTop, 
                                EUIFormClosingType.Soft);
                            newuicontrol.Instruments = new IInstrument[] { i };
                            this.instrumentsExpos[i.InstrumentStaticData.ID] = newuicontrol;
                        }

                        var uicontrol = this.instrumentsExpos[i.InstrumentStaticData.ID];
                        uicontrol.ContainingForm.Visibility = EUIFormVisibility.Invert;
                    }

                    break;

                case 13:
                    {
                        // I. Tracker button
                        if (!this.instrumentsTrackers.ContainsKey(i.InstrumentStaticData.ID))
                        {
                            var newuicontrol = new UIOrderTracker();
                            var uiform = newuicontrol.CreateContainingForm(
                                string.Format("Tracker for {0}", i.InstrumentStaticData.FriendlyName), EUIFormLayoutType.TitleBarAtTop, EUIFormClosingType.Soft);
                            newuicontrol.Instrument = i;
                            this.instrumentsTrackers[i.InstrumentStaticData.ID] = newuicontrol;
                        }

                        var uicontrol = this.instrumentsTrackers[i.InstrumentStaticData.ID];
                        uicontrol.ContainingForm.Visibility = EUIFormVisibility.Invert;
                    }

                    break;
            }
        }

        /// <summary>
        /// The virtual grid instruments_ ui grid query cell info.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void OnVirtualGridInstrumentsUIGridQueryCellInfo(object sender, VirtualGridEventArgs.QueryCellInfo e)
        {
            if (e.RowIndex >= this.instruments.Count)
            {
                return;
            }

            var i = this.instruments[e.RowIndex];

            switch (e.ColumnIndex)
            {
                case 0: // Code
                    e.Value = i.InstrumentStaticData.Code;
                    break;

                case 1: // Scope
                    e.Value = i.InstrumentStaticData.TradingScope;
                    break;

                case 2: // Bid Size
                    e.Value = i.MarketBook.Bids[0].HasValue ? ForgePrettyPrinter.Sizes.Format(i.MarketBook.Bids[0].Size) : "-";
                    break;

                case 3: // Bid
                    e.Value = i.MarketBook.Bids[0].HasValue
                                  ? ForgePrettyPrinter.Prices.Format(
                                        i.MarketBook.Bids[0].Price, i.InstrumentStaticData.TickSizeRule.Tick(i.MarketBook.Bids[0].Price))
                                  : "-";
                    break;

                case 4: // Ask
                    e.Value = i.MarketBook.Asks[0].HasValue
                                  ? ForgePrettyPrinter.Prices.Format(
                                        i.MarketBook.Asks[0].Price, i.InstrumentStaticData.TickSizeRule.Tick(i.MarketBook.Asks[0].Price))
                                  : "-";
                    break;

                case 5: // Ask size
                    e.Value = i.MarketBook.Asks[0].HasValue ? ForgePrettyPrinter.Sizes.Format(i.MarketBook.Asks[0].Size) : "-";
                    break;

                case 6: // Last
                    if (! i.MarketFields[EMarketField.Last].HasValue)
                    {
                        e.Value = "-";
                        break;
                    }

                    double pvalue = i.MarketFields[EMarketField.Last];
                    e.Value = ForgePrettyPrinter.Prices.Format(pvalue, i.InstrumentStaticData.TickSizeRule.Tick(pvalue));
                    break;

                case 7: // last size
                    if (!i.MarketFields[EMarketField.Last].HasValue)
                    {
                        e.Value = "-";
                        break;
                    }

                    int svalue = i.MarketFields[EMarketField.Last];
                    e.Value = ForgePrettyPrinter.Sizes.Format(svalue);
                    break;

                case 8: // Market book
                    e.Value = ">>";
                    break;

                case 9: // Market Fields
                    e.Value = ">>";
                    break;

                case 10: // PNL Traded
                    var ptcell = i.Expo[EExpoCellType.Traded];
                    if (ptcell == null)
                    {
                        e.Value = "-";
                        break;
                    }

                    e.Value = this.Round(i, ptcell.PL);
                    e.ToolTip = string.Empty + ptcell.PL;
                    break;

                case 11: // PNL Working
                    var pwcell = i.Expo[EExpoCellType.Working];
                    if (pwcell == null)
                    {
                        e.Value = "-";
                        break;
                    }

                    e.Value = this.Round(i, pwcell.PL);
                    e.ToolTip = string.Empty + pwcell.PL;
                    break;

                case 12: // Expo
                    e.Value = ">>";
                    break;

                case 13: // Order Tracker
                    e.Value = ">>";
                    break;
            }
        }

        /// <summary>
        /// The virtual grid instruments_ ui grid query row count.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void OnVirtualGridInstrumentsUIGridQueryRowCount(object sender, VirtualGridEventArgs.QueryRowCount e)
        {
            e.RowCount = this.instruments.Count;
        }

        /// <summary>
        /// The round.
        /// </summary>
        /// <param name="i">
        /// The i.
        /// </param>
        /// <param name="price">
        /// The price.
        /// </param>
        /// <returns>
        /// The round.
        /// </returns>
        private string Round(IInstrument i, double price)
        {
            var ticks = i.InstrumentStaticData.TickSizeRule.Tick(Math.Abs(price));
            return ForgePrettyPrinter.Prices.Format(price, ticks / 10);
        }

        #endregion

        /// <summary>
        /// The combo box item.
        /// </summary>
        internal class ComboBoxItem
        {
            #region Constructors and Destructors

            /// <summary>
            /// Initializes a new instance of the <see cref="ComboBoxItem"/> class.
            /// </summary>
            /// <param name="instrumentStaticData">
            /// The instrument static data.
            /// </param>
            public ComboBoxItem(IInstrumentStaticData instrumentStaticData)
            {
                this.InstrumentStaticData = instrumentStaticData;
            }

            #endregion

            #region Properties

            /// <summary>
            /// Gets InstrumentStaticData.
            /// </summary>
            public IInstrumentStaticData InstrumentStaticData { get; private set; }

            #endregion

            #region Public Methods

            /// <summary>
            /// The to string.
            /// </summary>
            /// <returns>
            /// The to string.
            /// </returns>
            public override string ToString()
            {
                return this.InstrumentStaticData.FriendlyName;
            }

            #endregion
        }
    }
}